home *** CD-ROM | disk | FTP | other *** search
/ 130 MIDI Tool Box / 130 MIDI Tool Box.iso / sysex / umpu.pas < prev   
Pascal/Delphi Source File  |  1991-04-08  |  7KB  |  256 lines

  1. Unit Umpu;
  2.  
  3. {
  4. ****************************************************************************
  5. This Unit is derived from an article written in the May 1989 issue of
  6. Electronic Musician Magazine entitled 'Handling MPU-401 Interrupts with
  7. Turbo Pascal' by William Millar.   The Code was coded into Unit form by
  8. John Sloan CIS. 71310,2267.
  9. ****************************************************************************
  10. }
  11.  
  12. Interface
  13.  
  14. Const
  15.      MPU_reset     = $ff;
  16.      MPU_UART_Mode = $3f;
  17.  
  18. var  Systemtick:longint absolute $40:$6c;
  19.      MPU_in_UART_mode  : Boolean;
  20.  
  21. Procedure Disable_CPU_Interrupts;
  22.      INLINE($FA);{CLI}
  23.  
  24. Procedure Enable_CPU_Interrupts;
  25.      INLINE($FB); {STI}
  26.  
  27. Procedure Disable_MPU_Interrupts;
  28.      INLINE($FA/$BA/$21/$00/$EC/$0C/$04/$EE/$FB);
  29.  
  30. Procedure Enable_MPU_Interrupts;
  31.      INLINE($FA/$BA/$21/$00/$EC/$24/$FB/$EE/$FB);
  32.  
  33. Procedure Ack_Int_to_PIC;
  34.      INLINE($BA/$20/$00/$B0/$20/$EE);
  35.  
  36. Function  Get_Data_From_MPU(Var data:Byte):Boolean;
  37.  
  38. Function  Get_Data_With_Timeout(Var data:Byte;
  39.                                 Expected:integer;
  40.                                 timeout:word):Boolean;
  41.  
  42. Procedure Send_Command_to_MPU(Command:Byte);
  43.  
  44. Procedure Send_Data_to_MPU(Data:Byte);
  45.  
  46. Procedure ClearMpuIn;
  47.  
  48. Procedure Mpu_Init;
  49.  
  50. Implementation
  51.  
  52. Uses Dos;
  53.  
  54. const
  55.      MPU_ack       =$fe;
  56.      MPU_Dataport  =$330;
  57.      MPU_Statport  =$331;
  58.      MPU_Comport   =$331;
  59.      MPU_Data_Available_Mask = $80;
  60.      MPU_Data_Ready_Mask     = $40;
  61.      MPU_Interrupt_Number    = 10;
  62.      Buffer_size  =4095;    {keep power of 2}
  63.      Buffer_start =0;
  64.      Buffer_End   =Buffer_size;
  65.  
  66. Type
  67.      Data_Buffer = Array[Buffer_Start..Buffer_End] of Byte;
  68.  
  69. Var
  70.      MPU_Indata_Buffer : Data_Buffer;
  71.      Buffer_Head,
  72.      Buffer_Tail       : Word;
  73.      Old_Int_Vec       : Pointer;
  74.      ExitSave          : Pointer;
  75.  
  76.  
  77. Procedure MPU_Interrupt_Handler;
  78.  
  79. {***************************************************************************
  80. This routine is called every time the hardware IRQ2 toggles as a result of
  81. data being received by the MPU-401.  The hardware vector to this routine is
  82. entered into the PC's interrupt vector table in the initialization section
  83. of this Unit.  The pseudocode is something like:
  84.  
  85.                Disable any further interrupts from bothering us
  86.                If the status port data available bit is reset then
  87.                   Write the data to the next location in the buffer
  88.                   If the pointer to this data location hasn't reached the
  89.                       end of the buffer then increment it, otherwise make
  90.                       it point to the beginning of the buffer
  91.                Enable the CPU interrupt system
  92.                Acknowledge to the PIC chip that we responded to this IRQ
  93.  
  94. *****************************************************************************
  95. }
  96.  
  97. Interrupt;
  98. Begin
  99.      Disable_MPU_Interrupts;
  100.      While((Port[MPU_statport] AND MPU_Data_Available_Mask)=0) DO
  101.           Begin
  102.                MPU_Indata_BUffer[Buffer_Head]:=Port[MPU_DataPort];
  103.                buffer_head:=(buffer_head+1) and Buffer_size;
  104.           End;
  105.       Enable_MPU_Interrupts;
  106.       ack_Int_to_PIC;
  107. End;
  108.  
  109. Function Get_Data_From_MPU;
  110. {
  111. ****************************************************************************
  112. Disable CPU interrupts
  113. If the buffer beginning pointer and the end pointer are different then we
  114.    must have data therefore:
  115.       Renable interrupts so we don't lose any data
  116.       Get the data from the buffer
  117.       If the pointer to this data isn't at the end of buffer increment it
  118.          otherwise reset it to point to the buffer's beginning
  119.       If data was available, pass the data back to the calling routine
  120.            as well as a boolean true (data available) otherwise
  121.            pass a boolean false (data not available)
  122.  
  123. *****************************************************************************
  124. }
  125.  
  126. Var
  127.    Valid:boolean;
  128.  
  129. Begin
  130.    Disable_MPU_Interrupts;
  131.    Valid:=(Buffer_Head <> Buffer_Tail);
  132.    Enable_MPU_Interrupts;
  133.    If (Valid) then
  134.       begin
  135.            Data:=MPU_Indata_Buffer[buffer_Tail];
  136.            buffer_tail:=(buffer_tail+1) and Buffer_size;
  137.       end;
  138.    Get_data_From_MPU:=valid
  139. end;{Get..}
  140.  
  141. {wait for data, ignore clock, timeout}
  142. Function  Get_Data_With_Timeout(Var data:Byte;
  143.                                 Expected:integer;
  144.                                 timeout:word):Boolean;
  145.  var t:longint;
  146.  begin
  147.   Get_data_with_timeout:=false;
  148.   t:=systemtick;
  149.   while not (Get_data_from_mpu(data) and
  150.              (data<>$F8) and
  151.              ((expected<0) or (data=expected))) do
  152.    if (systemtick-t)>=timeout then exit;
  153.  
  154.   Get_data_with_timeout:=true
  155.  end;
  156.  
  157. Procedure Send_Command_to_MPU;
  158.  
  159. Var
  160.    Data:Byte;
  161.    t:longint;
  162.  
  163. Begin
  164.  Disable_MPU_Interrupts;
  165.  
  166.  t:=systemtick;
  167.  While (Port[MPU_Statport] And MPU_Data_Ready_Mask)<>0 do
  168.   if systemtick-t>18 then exit;
  169.  
  170.  Port[MPU_Comport]:=Command;
  171.  
  172.  If (Command=MPU_Reset) and MPU_in_UART_Mode then Mpu_In_Uart_Mode:=false
  173.  else
  174.   begin
  175.    t:=systemtick;
  176.    Repeat
  177.     if (Port[MPU_Statport] and MPU_Data_Available_Mask)=0 then
  178.      begin
  179.       data:=port[Mpu_DataPort];
  180.       if data<>mpu_ack then
  181.        begin
  182.         MPU_Indata_buffer[buffer_head]:=data;
  183.         buffer_head:=succ(buffer_head) and Buffer_size;
  184.        end
  185.      end
  186.     else data:=0
  187.    Until (data=Mpu_ack) or (systemtick-t>18);
  188.   end;
  189.  If Command=Mpu_Uart_Mode then Mpu_In_Uart_Mode:=true;
  190.  Enable_mpu_Interrupts;
  191. end; {Send_Command..}
  192.  
  193. procedure Send_data_to_mpu(data:byte);
  194.  begin
  195.   Repeat
  196.   Until((Port[MPU_Statport] And MPU_Data_Ready_Mask)=0);
  197.   port[mpu_dataport]:=data
  198.  end;
  199.  
  200. procedure clearmpuin;
  201.  var b:byte;
  202.  begin
  203.   while get_data_from_mpu(b) do
  204.  end;
  205.  
  206.  
  207. {$F+} Procedure Uninstall_MPU401;
  208. Begin
  209.      ExitProc:=ExitSave;
  210.      Disable_MPU_Interrupts;
  211.      SetIntVec(MPU_Interrupt_Number,Old_Int_Vec);
  212. End;
  213.  
  214. procedure Mpu_Init;
  215.  var b,c:byte;
  216.      t:longint;
  217.      ok:boolean;
  218.  begin
  219.   Disable_Mpu_Interrupts;
  220. {flush in}
  221.   Buffer_Head := Buffer_Start;
  222.   Buffer_Tail := Buffer_Start;
  223.   b:=port[mpu_dataport];
  224.   while ((Port[MPU_Statport] and MPU_Data_Available_Mask)=0) do
  225.          b:=port[mpu_dataPort];
  226.  
  227.   ok:=false;
  228.   c:=3; {3 tries to reset}
  229.   repeat
  230.    t:=systemtick;
  231.    repeat
  232.     ok:=(Port[MPU_Statport] And MPU_Data_Ready_Mask)=0
  233.    until ok or (systemtick-t>18);
  234.    if not ok then exit;
  235.    port[mpu_ComPort]:=mpu_reset;
  236.    t:=systemtick;
  237.    repeat
  238.     ok:=((Port[MPU_Statport] And MPU_Data_Available_Mask)=0) and
  239.         (Port[Mpu_DataPort]=Mpu_ack);
  240.    until ok or (systemtick-t>18);
  241.    Dec(c);
  242.   until ok or (c=0);
  243.   Mpu_In_Uart_mode:=false;
  244.   Enable_mpu_interrupts;
  245.   Send_Command_to_mpu(mpu_Uart_mode);
  246.  end;
  247.  
  248. Begin {initialization Code}
  249.  ExitSave:=ExitProc;
  250.  ExitProc:=@Uninstall_MPU401;
  251.  GetIntVec(MPU_Interrupt_Number,Old_Int_Vec);
  252.  SetIntVec(MPU_Interrupt_Number,@MPU_Interrupt_Handler);
  253.  Mpu_init;
  254. End. {Init Code}
  255.  
  256.